﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Microsoft.AspNetCore.Mvc;
using shenghua.Authorization;
using shenghua.Commodity.Commodities.Dto;
using shenghua.Common.CustomValueType;
using shenghua.Common.Dto;
using shenghua.Extensions;
using shenghua.Marketing.SalesPromotions;

namespace shenghua.Commodity.Commodities
{
    public class CommodityAppService: shenghuaAppServiceBase, ICommodityAppService
    {
        private readonly CommodityManager _commodityManager;
        private readonly IRepository<Commodity> _commodityRepository;
        private readonly SalesPromotionManager _salesPromotionManager;

        public CommodityAppService(
            CommodityManager commodityManager,
            IRepository<Commodity> commodityRepository,
            SalesPromotionManager salesPromotionManager
            )
        {
            _commodityManager = commodityManager;
            _commodityRepository = commodityRepository;
            _salesPromotionManager = salesPromotionManager;
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<CommodityDto> CreateCommodity(CreateCommodityDto input)
        {
            Commodity commodity = new Commodity
            {
                Name = input.Name,
                CommodityWareId = input.CommodityWareId,
                Classes = new ValueArray<string>(input.Classes),
                Tags = new ValueArray<string>(input.Tags),
                Shelved = input.Shelved,
                IsRecommended = input.IsRecommended,
                IsEnabledShoppingOption = input.IsEnabledShoppingOption,
                Discountable = input.Discountable,
                IsDiscountPerLevel = input.IsDiscountPerLevel,
                SelectedShoppingOptionParameters = new ValueArray<string>(input.SelectedShoppingOptionParameters),
                ShoppingInfo = new CommodityShoppingInfoValueType
                {
                    Price = new Money(input.Price),
                    XPValue = input.XPValue,
                    Inventory = input.Inventory,
                    MinLimitCount = input.MinLimitCount,
                    MaxLimitCount = input.MaxLimitCount,
                    Picture = input.Picture,
                    Pictures = new ValueArray<string>(input.Pictures)
                },
                Description = input.Description
            };
            commodity.SetDiscounts(input.Discounts);
            commodity.SetSpecificationParameters(input.SpecificationParameters);

            List<CommodityShoppingOption> commodityShoppingOptions = new List<CommodityShoppingOption>();
            if(commodity.IsEnabledShoppingOption)
            {
                foreach (var item in input.ShoppingOptions)
                {
                    CommodityShoppingOption commodityShoppingOption = new CommodityShoppingOption
                    {
                        Price = new Money(item.Price),
                        XPValue = item.XPValue,
                        Inventory = item.Inventory,
                        MinLimitCount = item.MinLimitCount,
                        MaxLimitCount = item.MaxLimitCount,
                        Pictures = new ValueArray<string>(item.Pictures)
                    };
                    commodityShoppingOption.SetShoppingOptionParameters(item.ShoppingOptionParameters);
                    commodityShoppingOptions.Add(commodityShoppingOption);
                }
            }

            commodity = await _commodityManager.CreateCommodity(commodity, commodityShoppingOptions);
            return new CommodityDto(commodity, commodityShoppingOptions);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<CommodityDto> UpdateCommodity(UpdateCommodityDto input)
        {
            var item = await _commodityManager.GetCommodity(input.Id);
            item.Name = input.Name;
            item.CommodityWareId = input.CommodityWareId;
            item.Classes = new ValueArray<string>(input.Classes);
            item.Tags = new ValueArray<string>(input.Tags);
            item.Shelved = input.Shelved;
            item.IsRecommended = input.IsRecommended;
            item.IsEnabledShoppingOption = input.IsEnabledShoppingOption;
            item.Discountable = input.Discountable;
            item.IsDiscountPerLevel = input.IsDiscountPerLevel;
            item.SelectedShoppingOptionParameters = new ValueArray<string>(input.SelectedShoppingOptionParameters);
            item.ShoppingInfo.Price = new Money(input.Price);
            item.ShoppingInfo.XPValue = input.XPValue;
            item.ShoppingInfo.Inventory = input.Inventory;
            item.ShoppingInfo.MinLimitCount = input.MinLimitCount;
            item.ShoppingInfo.MaxLimitCount = input.MaxLimitCount;
            item.ShoppingInfo.Picture = input.Picture;
            item.ShoppingInfo.Pictures = new ValueArray<string>(input.Pictures);
            item.Description = input.Description;
            item.SetDiscounts(input.Discounts);
            item.SetSpecificationParameters(input.SpecificationParameters);

            item = await _commodityManager.UpdateCommodity(item);
            return new CommodityDto(item);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<CommodityDto> Get(EntityDto input)
        {
            Commodity commodity = await _commodityManager.GetCommodity(input.Id);
            List<CommodityShoppingOption> commodityShoppingOptions = await _commodityManager.GetCommodityShoppingOptions(input.Id);
            return new CommodityDto(commodity, commodityShoppingOptions);
        }

        public async Task<RealCommodityDto> GetShelved(GetRealCommodityDto input)
        {
            var member = await GetCurrentMemberAsync(false);
            var realCommodity = await _commodityManager.GetRealCommodity(member, input.CommodityId, input.ShoppingOptionId, false);
            if(realCommodity.Shelved) return new RealCommodityDto(realCommodity);
            else return new RealCommodityDto
            {
                CommodityName = realCommodity.CommodityName,
                Picture = realCommodity.Picture
            };
        }

        /// <summary>
        /// 得到详细产品信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<CommodityDescriptionDto> GetShelvedDescription(EntityDto input)
        {
            var item = await _commodityManager.GetCommodity(input.Id, true);
            var commodityShoppingOptions = await _commodityManager.GetCommodityShoppingOptions(input.Id);
            return new CommodityDescriptionDto
            {
                Description = item.Description,
                SpecificationParameters = item.SpecificationParameters,
                ShoppingOptions = commodityShoppingOptions.Select(r => new ShoppingOptionDto(r)).ToList()
            };
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<SearchResultDto<CommodityDto>> Search(SearchCommodityDto input)
        {
            var query = HandleQuery(input);
            int totalCount = query.Count();
            List<Commodity> list = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();
            return new SearchResultDto<CommodityDto>
            {
                TotalCount = totalCount,
                Items = list.Select(r => new CommodityDto
                {
                    Id = r.Id,
                    Name = r.Name,
                    CommodityWareId = r.CommodityWareId,
                    Classes = r.Classes.Items,
                    Tags = r.Tags.Items,
                    Inventory = r.ShoppingInfo.Inventory,
                    Shelved = r.Shelved,
                    CreationTime = r.CreationTime,
                    CreatorUserId = r.CreatorUserId,
                    IsEnabledShoppingOption = r.IsEnabledShoppingOption,
                    SelectedShoppingOptionParameters = r.SelectedShoppingOptionParameters.Items,
                    Picture = r.ShoppingInfo.Picture
                }).ToList()
            };
        }

        public async Task<SearchResultDto<RealCommodityDto>> SearchShelved(SearchCommodityDto input)
        {
            var query = HandleQuery(input);
            query = query.Where(r => r.Shelved == true);
            int totalCount = query.Count();
            List<Commodity> items = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            var member = await GetCurrentMemberAsync(false);

            List<RealCommodityDto> realCommodities = new List<RealCommodityDto>();
            foreach (var item in items)
            {
                var realCommodity = await _commodityManager.GetRealCommodity(member, item, null);
                realCommodities.Add(new RealCommodityDto(realCommodity));
            }

            return new SearchResultDto<RealCommodityDto>
            {
                TotalCount = totalCount,
                Items = realCommodities
            };
        }

        private IQueryable<Commodity> HandleQuery(SearchCommodityDto input)
        {
            var query = _commodityRepository.GetAll();

            if (!string.IsNullOrWhiteSpace(input.Name))
            {
                query = query.Where(r => r.Name.Contains(input.Name));
            }

            if (input.CommodityWareId.IsSearchValid())
            {
                query = query.Where(r => r.CommodityWareId == input.CommodityWareId);
            }

            if (input.Classes.Count > 0)
            {
                foreach (var item in input.Classes)
                {
                    if (string.IsNullOrWhiteSpace(item)) continue;
                    if (item.Contains("[]"))
                    {
                        var temp = item.Replace("[]", "");
                        query = query.Where(r => r.Classes.StringValue.Contains(temp) && !r.Classes.StringValue.Contains(temp + "["));
                    }
                    else query = query.Where(r => r.Classes.StringValue.Contains(item));
                }
            }

            if (input.Tags.Count > 0)
            {
                foreach (var tag in input.Tags)
                {
                    if (string.IsNullOrWhiteSpace(tag)) continue;
                    query = query.Where(r => r.Tags.Items.Contains(tag));
                }
            }

            if(input.MinPrice != null)
            {
                query = query.Where(r => r.ShoppingInfo.Price >= input.MinPrice);
            }
            
            if (input.MaxPrice != null)
            {
                query = query.Where(r => r.ShoppingInfo.Price <= input.MaxPrice);
            }

            if(!string.IsNullOrWhiteSpace(input.Search))
            {
                switch(input.SearchTarget)
                {
                    case "id": query = query.Where(r => r.Id.ToString() == input.Search); break;
                    case "name": query = query.Where(r => r.Name.Contains(input.Search)); break;
                    case "tag": query = query.Where(r => r.Tags.Items.Contains(input.Search)); break;
                }
            }

            if(input.IsRecommended)
            {
                query = query.Where(r => r.IsRecommended);
            }

            if(input.IsInPromotion)
            {
                var ids = _salesPromotionManager.GetInPromotionCommodityIds().Result;
                if(ids != null)
                {
                    query = query.Where(r => ids.Contains(r.Id));
                }
            }

            if(input.IsOrderByAsc("price"))
            {
                query = query.OrderBy(r => r.ShoppingInfo.Price);
            }
            else if (input.IsOrderByDesc("price"))
            {
                query = query.OrderByDescending(r => r.ShoppingInfo.Price);
            }else if (input.IsOrderByAsc("name"))
            {
                query = query.OrderBy(r => r.Name);
            }
            else if (input.IsOrderByDesc("name"))
            {
                query = query.OrderByDescending(r => r.Name);
            }else
            {
                query = query.OrderByDescending(r => r.CreationTime);
            }

            return query;
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        [HttpPost]
        public async Task Delete(DeleteDto input)
        {
            foreach(var id in input.Ids)
            {
                await _commodityManager.DeleteCommodity(id);
            }
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task Shelved(EntityDto input)
        {
            await _commodityManager.Shelved(input.Id, true);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task NotShelved(EntityDto input)
        {
            await _commodityManager.Shelved(input.Id, false);
        }

        [HttpPost]
        public async Task<List<CommodityDto>> GetProfiles(BatchIntIdDto input)
        {
            var items = _commodityRepository.GetAll().Where(r => input.Ids.Contains(r.Id)).ToList();
            return items.Select(r => new CommodityDto
            {
                Id = r.Id,
                Name = r.Name,
                Classes = r.Classes.Items
            }).ToList();
        }

        #region 购物选项
        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task EnabledShoppingOption(EntityDto input)
        {
            await _commodityManager.EnabledShoppingOption(input.Id, true);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task DisabledShoppingOption(EntityDto input)
        {
            await _commodityManager.EnabledShoppingOption(input.Id, false);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<ShoppingOptionDto> AddShoppingOption(CreateShoppingOptionDto input)
        {
            CommodityShoppingOption item = new CommodityShoppingOption();
            input.MapTo(item);
            Commodity commodity = await _commodityManager.GetCommodity(input.CommodityId);
            await _commodityManager.AddShoppingOption(commodity, item);
            return new ShoppingOptionDto(item);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<ShoppingOptionDto> UpdateShoppingOption(UpdateShoppingOptionDto input)
        {
            var item = await _commodityManager.GetCommodityShoppingOption(input.Id);
            input.MapTo(item);
            await _commodityManager.UpdateShoppingOption(item);
            return new ShoppingOptionDto(item);
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        [HttpPost]
        public async Task DeleteShoppingOption(DeleteDto input)
        {
            foreach(int id in input.Ids)
            {
                await _commodityManager.DeleteShoppingOption(id);
            }
        }

        [AbpAuthorize(PermissionNames.CommodityManagement)]
        public async Task<List<ShoppingOptionDto>> GetAllShoppingOptions(EntityDto input)
        {
            var items = await _commodityManager.GetCommodityShoppingOptions(input.Id);
            return items.Select(r => new ShoppingOptionDto(r)).ToList();
        }
        #endregion
    }
}
